package org.hackystat.devcathlon.engine.event.impl;

import static org.junit.Assert.assertEquals;

import javax.xml.datatype.XMLGregorianCalendar;

import org.hackystat.devcathlon.configuration.ConfigurationManager;
import org.hackystat.devcathlon.engine.event.Event;
import org.hackystat.devcathlon.engine.event.EventScore;
import org.hackystat.devcathlon.engine.match.Match;
import org.hackystat.devcathlon.engine.team.Team;
import org.hackystat.devcathlon.engine.test.DevcathlonTestHelper;
import org.hackystat.sensorbase.resource.projects.jaxb.Project;
import org.hackystat.utilities.tstamp.Tstamp;
import org.junit.Test;
import org.junit.BeforeClass;


/**
 * Tests the Reward Improved Coverage Event.
 * @author Scheller Sanchez
 */
public class TestRewardImprovedCoverage extends DevcathlonTestHelper {
  
  private String teamName = "TestTeam";
  private String teamOwner = "TeamOwner";
  private String matchName = "TestMatch";
  private String member1 = "Member1";
  private String member2 = "Member2";
  
//  private static int baseScore = 10;
  private static int bonusImprovedDays = 3;
  private static int bonusPercentImprovement = 5;
  private static int bonusScoreWeight = 20;
  private static int percentImprovement = 10;
//  private static int wakeupInterval = 1;

  /**
   * Sets up the DevcathlonConfiguration for use in these test cases. 
   * @throws Exception If problems occur setting up the configuration. 
   */
  @BeforeClass
  public static void setupConfiguration() throws Exception {
    // Set up the testing DevcathlonConfiguration for the event KeepTheCoverageHigh.
    String eventName = RewardImprovedCoverage.eventName;
    ConfigurationManager configManager = ConfigurationManager.getInstance();
    configManager.setBaseScoreWeight(eventName, 1);
    configManager.getConfiguration(eventName);
    configManager.setWakeupInterval(eventName, 1);
    //configManager.addProperty(eventName, RewardImprovedCoverage.wakeupIntervalKey,
    //    String.valueOf(wakeupInterval));
    //configManager.addProperty(eventName, RewardImprovedCoverage.baseScoreWeightKey, 
    //    String.valueOf(baseScore));
    configManager.addProperty(eventName, RewardImprovedCoverage.bonusImprovedDaysKey, 
        String.valueOf(bonusImprovedDays));
    configManager.addProperty(eventName, RewardImprovedCoverage.bonusPercentImprovementKey, 
        String.valueOf(bonusPercentImprovement));
    configManager.addProperty(eventName, RewardImprovedCoverage.bonusScoreWeightKey, 
        String.valueOf(bonusScoreWeight));
    configManager.addProperty(eventName, RewardImprovedCoverage.percentImprovementKey, 
        String.valueOf(percentImprovement));
    configManager.addProperty(eventName, RewardImprovedCoverage.typeOfCoverageKey, "Line");
    
    
  }
  
  /**
   * Tests this event when there is no sensor data for this team.
   * @throws Exception If there is a bug.
   */
  @Test
  public void testNoData() throws Exception {
    // Create the team.
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Create the event instance.
    Event event = new RewardImprovedCoverage();
    
    // Create a simple match containing a single team, a single project and this event.
    Match match = addSimpleMatch(matchName, team, getProject(teamOwner, teamName),event);

    // Test the event with no sensor data.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    
    assertEquals("Check base score 0", 0, score.getBaseScore());
    assertEquals("Check bonus score 0", 0, 
        score.getBonusScore(RewardImprovedCoverage.bonusScoreWeightKey));
    assertEquals("check total points 0", 0, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
    
    
  }
  
  /**
   * Tests this event when coverage has increased by 10%
   * from the previous day.
   * @throws Exception If there is a bug.
   */
  @Test
  public void testCoverageIncrease() throws Exception {
    // Create the team.
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Create the test days.
    XMLGregorianCalendar day1 = Tstamp.makeTimestamp();
    XMLGregorianCalendar day2 = Tstamp.incrementDays(day1, 1);
    
    // Create the event instance.
    Event event  = new RewardImprovedCoverage();
    
    // Create a simple match containing a single team, a single project and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    // Send some coverage for day1.
    makeCoverageData(team.getOwner(), project, day1, 50, 100);
    
    // Test score for a project with no coverage prior to first day.
    EventScore score = event.computeScore(match, team, day1);
    assertEquals("Check base score 0", 0, score.getBaseScore());
    
    // Test score for a project  with project after two days.
    makeCoverageData(team.getOwner(), project, day2, 60, 100);
    score = event.computeScore(match, team, day2);
    assertEquals("Check base score 1", 1, event.computePoints(score));
            
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
    
  }
  
  /**
   * Tests this event when coverage from previous day decreased
   * or stays the same.
   * @throws Exception If there is a bug.
   */
  @Test
  public void testCoverageDecreases() throws Exception {
    // Create the team.
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Creates the test days.
    XMLGregorianCalendar day1 = Tstamp.makeTimestamp();
    XMLGregorianCalendar day2 = Tstamp.incrementDays(day1, 1);
    XMLGregorianCalendar day3 = Tstamp.incrementDays(day2, 1);
    XMLGregorianCalendar day4 = Tstamp.incrementDays(day3, 1);
    
    // Create simple match.
    Event event = new RewardImprovedCoverage();
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    // Sends decreasing coverage for day1 and day2.
    makeCoverageData(team.getOwner(), project, day1, 50, 100);
    EventScore score = event.computeScore(match, team, day1);
    makeCoverageData(team.getOwner(), project, day2, 40, 100);
    score = event.computeScore(match, team, day2);
    
    // Test score for decreasing project.
    assertEquals("Check score -1", -1, event.computePoints(score));
    
    // Test score for coverage remaining the same.
    makeCoverageData(team.getOwner(), project, day3, 50, 100);
    score = event.computeScore(match, team, day3);
    makeCoverageData(team.getOwner(), project, day4, 50, 100);
    score = event.computeScore(match, team, day4);
    assertEquals("Check score 0", 0, event.computePoints(score)); 
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
    
  }
  
  /**
   * Tests this event to receive bonus by increase coverage by 5%
   * over three days.
   * @throws Exception If there is a bug.
   * 
   */
  @Test
  public void testCoverageBonus() throws Exception {
    // Create the team.
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    //Creates the test days.
    XMLGregorianCalendar day1 = Tstamp.makeTimestamp();
    XMLGregorianCalendar day2 = Tstamp.incrementDays(day1, 1);
    XMLGregorianCalendar day3 = Tstamp.incrementDays(day2, 1);
    XMLGregorianCalendar day4 = Tstamp.incrementDays(day3, 1);
    
    // Create simple match.
    Event event = new RewardImprovedCoverage();
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    // Sends coverage data; data begins to increase at day 2..
    makeCoverageData(team.getOwner(), project, day1, 50, 100);
    EventScore score = event.computeScore(match, team, day1);
    makeCoverageData(team.getOwner(), project, day2, 55, 100);
    score = event.computeScore(match, team, day2);
    makeCoverageData(team.getOwner(), project, day3, 60, 100);
    score = event.computeScore(match, team, day3);
    makeCoverageData(team.getOwner(), project, day4, 65, 100);
    score = event.computeScore(match, team, day4);
    // 0 base points + 20 bonus points = 20 points
    assertEquals("Check Bonus Score 20", 20, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
    
    
  }

}
